#include "data/entry.h"
#include "files/directory.h"
#include "functional/functional.h"
#include "scanner/base_processor.h"
#include "scanner/base_scanner.h"
#include "scanner/multi_part_filter.h"
#include "scanner/supported_files_filter.h"

#include <algorithm>

namespace Tvimeg
{
	void BaseScanner::Scan(const Directory& directory, const BaseProcessor& processor) const
	{
		ScanDirectories(directory, processor);
		ScanFiles(directory, processor);
	}

	void BaseScanner::ScanDirectories(const Directory& directory, const BaseProcessor& processor) const
	{
		// get the list of sub directories
		Directory::DirectoryList directories;
		directory.GetDirectories(directories);

		// sort the sub directories and scan each of them
		std::sort(directories.begin(), directories.end());
		std::for_each(directories.begin(), directories.end(), Bind(*this, &BaseScanner::Scan, processor));
	}

	void BaseScanner::ScanFiles(const Directory& directory, const BaseProcessor& processor) const
	{
		// get all the files in this folder
		Directory::FileList files;
		directory.GetFiles(files);

		// remove files with extensions that are not supported and sort the remaining files
		files.erase(std::remove_if(files.begin(), files.end(), std::not1(SupportedFilesFilter())), files.end());
		std::sort(files.begin(), files.end());

		// create an object for each of the files
		for (Directory::FileList::iterator current = files.begin(); current != files.end(); ++current)
		{
			// add the first file
			Entry entry(*current);

			// also add any additional multi part files
			std::size_t commonNameLength = 0;
			MultiPartFilter multiPartFilter(*current, commonNameLength);
			Directory::FileList::iterator multiPart = std::find_if(current + 1, files.end(), multiPartFilter);
			while (multiPart != files.end())
			{
				// add the extra file
				entry.AddFile(*multiPart, commonNameLength);

				// we don't want to add this file again, so remove it from the file list
				files.erase(multiPart);

				// find the next part
				multiPart = std::find_if(current + 1, files.end(), multiPartFilter);
			}

			processor.Process(entry);
		}
	}
}
